﻿/*
* 命名空间: Service.Library.IIS
*
* 功 能： IIS帮助类
*
* 类 名： IISWorker
*
* Version   变更日期            负责人     变更内容
* ─────────────────────────────────────────────────
* V1.0.1    2020/5/8 11:50:53 	罗维    创建
* ─────────────────────────────────────────────────
*
* Copyright (c) 2020 ZHDL Corporation. All rights reserved.
*/
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Net;
using System.Net.NetworkInformation;
using System.ServiceProcess;
using System.Text.RegularExpressions;


namespace Service.Library
{
    /// <summary>
    /// IIS帮助类
    /// </summary>
    public class IISWorkerClient
    {
        /// <summary>
        /// 获取配置
        /// </summary>
        public WebsiteInfo Config { get; private set; }

        /// <summary>
        /// 不公开默认构造函数，请通过InitZipService来创建实例
        /// </summary>
        private IISWorkerClient() { }

        /// <summary>
        /// 初始化服务
        /// </summary>
        /// <param name="config">配置对象</param>
        /// <returns>当前压缩服务</returns>
        public static IISWorkerClient InitService(WebsiteInfo config)
        {
            IISWorkerClient ser = new IISWorkerClient();
            ser.Config = config;
            return ser;
        }

        #region IIS服务管理

        /// <summary>
        /// 判断IIS服务是否存在
        /// </summary>
        /// <param name="tem"></param>
        /// <returns></returns>
        public  bool ExistIISService(string tem)
        {
            bool ExistFlag = false;
            ServiceController[] service = ServiceController.GetServices();
            for (int i = 0; i < service.Length; i++)
            {
                if (service[i].ServiceName.ToString() == tem)
                {
                    ExistFlag = true;
                    break;
                }
            }
            return ExistFlag;
        }

        /// <summary>
        /// 获取本地IIS版本方法
        /// </summary>
        public string GetIISMajorVersion()
        {
            string result = string.Empty;
            try
            {
                double majorVersion = 0;
                var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\INetStp");
                if (key != null)
                {
                    majorVersion = Convert.ToDouble(key.GetValue("MajorVersion"));
                }
                int left = Convert.ToInt32(majorVersion);
                int right = Convert.ToInt32((majorVersion - left) * 10);

                result = Convert.ToString(left) + "." + Convert.ToString(right);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return result;
        }

        /// <summary>
        /// 获取本地IIS版本
        /// </summary>
        /// <returns></returns>
        public string GetIIsVersion()
        {
            try
            {
                DirectoryEntry entry = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/INFO");
                string version = entry.Properties["MajorIISVersionNumber"].Value.ToString();
                return version;
            }
            catch
            {
                //说明一点:IIS5.0中没有(int)entry.Properties["MajorIISVersionNumber"].Value;属性，将抛出异常 证明版本为 5.0
                return string.Empty;
            }
        }

        /// <summary>
        /// 为新网站查找未使用的ID值
        /// </summary>
        /// <returns></returns>
        public int SiteId()
        {
            DirectoryEntry root = new DirectoryEntry($"IIS://{Config.IP}/W3SVC");
            //为新网站查找未使用的ID值
            int siteID = 1;
            foreach (DirectoryEntry e in root.Children)
            {
                if (e.SchemaClassName == "IIsWebServer")
                {
                    int ID = Convert.ToInt32(e.Name);
                    if (ID >= siteID)
                    {
                        siteID = ID + 1;
                    }
                }
            }
            return siteID;
        }

        #endregion

        #region IIS站点操作

        /// <summary>
        /// 创建虚拟目录网站
        /// </summary>
        /// <param name="isCreateAppPool">是否创建新的应用程序池</param>
        /// <returns></returns>
        public ServiceResultInfo CreateWebSite(bool isCreateAppPool)
        {

            ServiceResultInfo result =new ServiceResultInfo();
            try
            {
                //1、判断端口是否被占用
                var portInUse = PortInUse(int.Parse(Config.Port));
                if (!portInUse)
                {

                    DirectoryEntry root = new DirectoryEntry($"IIS://{Config.IP}/W3SVC");

                    //为新WEB站点查找一个未使用的ID
                    int siteID = 1;
                    foreach (DirectoryEntry e in root.Children)
                    {
                        if (e.SchemaClassName == "IIsWebServer")
                        {
                            int ID = Convert.ToInt32(e.Name);
                            if (ID >= siteID) { siteID = ID + 1; }
                        }
                    }
                    // 创建WEB站点
                    DirectoryEntry site = (DirectoryEntry)root.Invoke("Create", "IIsWebServer", siteID);
                    site.Invoke("Put", "ServerComment", Config.SiteName);
                    site.Invoke("Put", "KeyType", "IIsWebServer");
                    site.Invoke("Put", "ServerBindings", Config.DomainPort + ":");
                    site.Invoke("Put", "ServerState", 2);
                    site.Invoke("Put", "FrontPageWeb", 1);
                    site.Invoke("Put", "DefaultDoc", "index.aspx,index.htm,index.html,default.aspx,default.htm,default.html");
                    // site.Invoke("Put", "SecureBindings", ":443:");
                    site.Invoke("Put", "ServerAutoStart", 1);
                    site.Invoke("Put", "ServerSize", 1);
                    site.Invoke("SetInfo");
                    // 创建应用程序虚拟目录
                    DirectoryEntry siteVDir = site.Children.Add("Root", "IISWebVirtualDir");
                    siteVDir.Properties["AppIsolated"][0] = 2;
                    siteVDir.Properties["Path"][0] = Config.PhysicalPath;
                    siteVDir.Properties["AccessFlags"][0] = 513;
                    siteVDir.Properties["FrontPageWeb"][0] = 1;
                    siteVDir.Properties["AppRoot"][0] = "LM/W3SVC/" + siteID + "/Root";
                    siteVDir.Properties["AppFriendlyName"][0] = "Root";

                    if (isCreateAppPool&&!IsAppPoolName(Config.SiteName))
                    {
                        DirectoryEntry apppools = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                        DirectoryEntry newpool = apppools.Children.Add(Config.AppPool, "IIsApplicationPool");
                        newpool.Properties["ManagedRuntimeVersion"][0] = Config.FrameworkVersion.Contains("无托管") ? "v4.0" : Config.FrameworkVersion;//v4.0  v2.0
                        newpool.Properties["ManagedPipelineMode"][0] = Config.HostedMode; //0:集成模式 1:经典模式  
                        newpool.CommitChanges();
                        siteVDir.Properties["AppPoolId"][0] = Config.AppPool;

                    }
                    siteVDir.CommitChanges();
                    site.CommitChanges();

                    result.Msg = "成功设置站点";
                    result.Code = ErrorCode.SetSucceed;
                }
                else
                {
                    //端口被占用
                    result.Msg = "http端口已被占用";
                    result.Code = ErrorCode.HttpPortUsed;
                    result.Success = false;
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                //端口被占用
                result.Msg = ex.ToString();
                result.Code = ErrorCode.HttpPortUsed;
                result.Success = false;
            }

            return result;
        }


        /// <summary>
        /// 获取指定网站siteID
        /// </summary>
        /// <param name="siteName">站点名称</param>
        /// <returns></returns>
        public string GetWebSiteNum(string siteName)
        {
            Regex regex = new Regex(siteName);
            string tmpStr;
            DirectoryEntry ent = new DirectoryEntry($"IIS://{Config.IP}/W3SVC");
            foreach (DirectoryEntry child in ent.Children)
            {
                if (child.SchemaClassName == "IIsWebServer")
                {
                    if (child.Properties["ServerBindings"].Value != null)
                    {
                        tmpStr = child.Properties["ServerBindings"].Value.ToString();
                        if (regex.Match(tmpStr).Success)
                        {
                            return child.Name;
                        }
                    }
                    if (child.Properties["ServerComment"].Value != null)
                    {
                        tmpStr = child.Properties["ServerComment"].Value.ToString();
                        if (regex.Match(tmpStr).Success)
                        {
                            return child.Name;
                        }
                    }
                }
            }
            return "";
        }

        /// <summary>
        /// 获取IIS站点列表
        /// </summary>
        public List<WebsiteInfo> GetServerBindings()
        {
            List<WebsiteInfo> iisList = new List<WebsiteInfo>();
            DirectoryEntry ent = new DirectoryEntry($"IIS://{Config.IP}/W3SVC");
            foreach (DirectoryEntry child in ent.Children)
            {
                if (child.SchemaClassName.Equals("IIsWebServer", StringComparison.OrdinalIgnoreCase))
                {
                    if (child.Properties["ServerBindings"].Value != null)
                    {
                        object objectArr = child.Properties["ServerBindings"].Value;
                        string serverBindingStr = string.Empty;
                        if (objectArr is Array)//如果有多个绑定站点时
                        {
                            object[] objectToArr = (object[])objectArr;
                            serverBindingStr = objectToArr[0].ToString();
                        }
                        else//只有一个绑定站点
                        {
                            serverBindingStr = child.Properties["ServerBindings"].Value.ToString();
                        }
                        WebsiteInfo iisInfo = new WebsiteInfo();
                        iisInfo.DomainPort = serverBindingStr;
                        iisInfo.AppPool = child.Properties["AppPoolId"].Value.ToString();//应用程序池
                        iisInfo.SiteName = child.Properties["SiteName"].Value.ToString();

                        iisInfo.PhysicalPath = GetWebsitePhysicalPath(child);
                        iisList.Add(iisInfo);
                    }
                }
            }
            return iisList;
        }

        /// <summary>
        /// 得到网站的物理路径
        /// </summary>
        /// <param name="rootEntry">网站节点</param>
        /// <returns></returns>
        public string GetWebsitePhysicalPath(DirectoryEntry rootEntry)
        {
            string physicalPath = "";
            foreach (DirectoryEntry childEntry in rootEntry.Children)
            {
                if ((childEntry.SchemaClassName == "IIsWebVirtualDir") && (childEntry.Name.ToLower() == "root"))
                {
                    if (childEntry.Properties["Path"].Value != null)
                    {
                        physicalPath = childEntry.Properties["Path"].Value.ToString();
                    }
                    else
                    {
                        physicalPath = "";
                    }
                }
            }
            return physicalPath;
        }

        /// <summary>
        /// 启动网站
        /// </summary>
        /// <param name="serviceInfo"></param>
        /// <param name="siteName"></param>
        public ServiceResultInfo StartWebSite()
        {
            ServiceResultInfo result = new ServiceResultInfo();
            try
            {
                string siteNum = GetWebSiteNum(Config.SiteName);
                DirectoryEntry siteEntry = new DirectoryEntry($"IIS://{Config.IP}/w3svc/{siteNum}");
                siteEntry.Invoke("Start", new object[] { });

                result.Code = ErrorCode.iisStart;
                result.Msg = "iis启动成功";
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return result;
        }

        /// <summary>
        /// 停止网站
        /// </summary>
        public ServiceResultInfo StopWebSite()
        {
            ServiceResultInfo result = new ServiceResultInfo();

            try
            {
                string siteNum = GetWebSiteNum(Config.SiteName);
                DirectoryEntry siteEntry = new DirectoryEntry($"IIS://{Config.IP}/w3svc/{siteNum}");
                siteEntry.Invoke("Stop", new object[] { });

                result.Code = ErrorCode.iisStop;
                result.Msg = "iis停止成功";
            }
            catch (Exception ex)
            {
                throw ex;
            }
          
            return result;
        }

        /// <summary>
        /// 删除站点
        /// </summary>
        /// <param name="siteName"></param>
        public ServiceResultInfo DelSite()
        {
            ServiceResultInfo result = new ServiceResultInfo();

            try
            {
                string siteNum = GetWebSiteNum(Config.SiteName);
                DirectoryEntry siteEntry = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/{siteNum}");//从活动目录中获取IIS对象。

                DirectoryEntry rootEntry = new DirectoryEntry($"IIS://{Config.IP}/W3SVC");
                rootEntry.Children.Remove(siteEntry);
                rootEntry.CommitChanges();

                DeleteAppPool(Config.SiteName);

                result.Code = ErrorCode.iisStop;
                result.Msg = "iis停止成功";

            }
            catch (Exception ex)
            {
                throw ex;
            }
            return result;
        }

        /// <summary>
        /// 获取网站状态
        /// </summary>
        public ServiceResultInfo ViewSiteState()
        {
            ServiceResultInfo result = new ServiceResultInfo();
            try
            {
                string siteNum = GetWebSiteNum(Config.SiteName);
                if (!string.IsNullOrEmpty(siteNum))
                {
                    DirectoryEntry directoryEntry = new DirectoryEntry($"IIS://localhost/W3SVC");///{siteNum}
                    var ienum = directoryEntry.Children.GetEnumerator();
                    while (ienum.MoveNext())
                    {
                        DirectoryEntry entrypool = (DirectoryEntry)ienum.Current;
                        PropertyCollection ppC = entrypool.Properties;
                        if (entrypool.SchemaClassName == "IIsWebServer")
                        {
                            //string[] serverBind = ppC["ServerBindings"][0].ToString().Split(':');//获取网站绑定的IP，端口，主机头
                            //string EnableDeDoc = ppC["EnableDefaultDoc"][0].ToString();
                            //string DefaultDoc = ppC["DefaultDoc"][0].ToString();//默认文档
                            //string MaxConnections = ppC["MaxConnections"][0].ToString();//iis连接数,-1为不限制
                            //string ConnectionTimeout = ppC["ConnectionTimeout"][0].ToString();//连接超时时间
                            //string MaxBandwidth = ppC["MaxBandwidth"][0].ToString();//最大绑定数
                            string ServerState = ppC["ServerState"][0].ToString();//运行状态
                            //HostInfo += "站点描述：" + ppC["ServerComment"][0].ToString() + "<br>IP地址：" + serverBind[0].ToString() + "<br>TCP端口：" + serverBind[1].ToString() + "<br>主机头：" + serverBind[2].ToString() + "<br>";//获取IIS下所有站点名称
                            //HostInfo += "启用默认文档：" + EnableDeDoc + "<br>";
                            //HostInfo += "默认文档：" + DefaultDoc + "<br>";
                            //HostInfo += "最大连接：" + MaxConnections + "<br>";
                            //HostInfo += "连接超时：" + ConnectionTimeout + "<br>";
                            //HostInfo += "最大绑定数：" + MaxBandwidth + "<br>";
                            //HostInfo += "运行状态：" + ServerState + "<br><br>";

                            result.Code =int.Parse(ServerState);
                            result.Msg = "获取到状态！";
                        }
                    }
                }
                else
                {
                    result.Code = 0;
                    result.Msg = "网站不存在！";
                }
            }
            catch 
            {
                result.Success = false;
                result.Msg = "不是本机网站，拒绝访问！";
            }
            return result;
        }
        #endregion

        #region 域名绑定方法
        /// <summary>
        /// 域名绑定方法
        /// </summary>
        /// <param name="siteid"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="domain"></param>
        /// <returns></returns>
        public int AddHostHeader(int siteid, string ip, int port, string domain)//增加主机头（站点编号.ip.端口.域名）
        {
            int mark = 0;
            try
            {
                DirectoryEntry site = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/{siteid}");
                PropertyValueCollection serverBindings = site.Properties["ServerBindings"];
                string headerStr = string.Format("{0}:{1}:{2}", ip, port, domain);
                if (!serverBindings.Contains(headerStr))
                {
                    serverBindings.Add(headerStr);
                }
                site.CommitChanges();
                mark = 1;
            }
            catch
            {
                mark = 0;
            }
            return mark;
        }
        #endregion

        #region 删除主机头

        /// <summary>
        /// 删除主机头
        /// </summary>
        /// <param name="siteid"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="domain"></param>
        public void DeleteHostHeader(int siteid, string ip, int port, string domain)//删除主机头（站点编号.ip.端口.域名）
        {
            DirectoryEntry site = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/{siteid}");
            PropertyValueCollection serverBindings = site.Properties["ServerBindings"];
            string headerStr = string.Format("{0}:{1}:{2}", ip, port, domain);
            if (serverBindings.Contains(headerStr))
            {
                serverBindings.Remove(headerStr);
            }
            site.CommitChanges();
        }
        #endregion

        #region 应用程序池

        /// <summary>
        /// 创建程序池
        /// </summary>
        /// <param name="AppPoolName"></param>
        /// <returns></returns>
        private  DirectoryEntry CreateAppPool(string AppPoolName)
        {
            DirectoryEntry newpool = new DirectoryEntry();
            if (!IsAppPoolName(AppPoolName))
            {
                DirectoryEntry appPools = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                newpool = appPools.Children.Add(AppPoolName, "IIsApplicationPool");
                newpool.CommitChanges();
            }
            return newpool;
        }

        /// <summary>
        /// 判断应用程序池是否存在
        /// </summary>
        /// <param name="AppPoolName"></param>
        /// <returns></returns>
        private bool IsAppPoolName(string AppPoolName)
        {
            bool result = false;
            DirectoryEntry appPools = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
            foreach (DirectoryEntry getdir in appPools.Children)
            {
                if (getdir.Name.Equals(AppPoolName))
                {
                    result = true;
                }
            }
            return result;
        }


        /// <summary>
        /// 删除应用程序池
        /// </summary>
        /// <param name="AppPoolName"></param>
        public void DeleteAppPool(string AppPoolName)
        {
            bool ExistAppPoolFlag = false;
            try
            {
                DirectoryEntry apppools = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                foreach (DirectoryEntry a in apppools.Children)
                {
                    if (a.Name == AppPoolName)
                    {
                        ExistAppPoolFlag = true;
                        a.DeleteTree();
                    }
                }
                if (ExistAppPoolFlag == false)
                {
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        ///启动应用程序池
        /// </summary>
        /// <param name="AppPoolName"></param>
        public  void StartAppPool(string AppPoolName)
        {
            try
            {
                DirectoryEntry appPool = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                DirectoryEntry findPool = appPool.Children.Find(AppPoolName, "IIsApplicationPool");
                findPool.Invoke("Start", null);
                appPool.CommitChanges();
                appPool.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        ///停止应用程序池
        /// </summary>
        /// <param name="AppPoolName"></param>
        public  void StopAppPool(string AppPoolName)
        {
            try
            {
                DirectoryEntry appPool = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                DirectoryEntry findPool = appPool.Children.Find(AppPoolName, "IIsApplicationPool");
                findPool.Invoke("Stop", null);
                appPool.CommitChanges();
                appPool.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        ///回收应用程序池
        /// </summary>
        /// <param name="AppPoolName"></param>
        public  void RecycleAppPool(string AppPoolName)
        {
            try
            {
                DirectoryEntry appPool = new DirectoryEntry($"IIS://{Config.IP}/W3SVC/AppPools");
                DirectoryEntry findPool = appPool.Children.Find(AppPoolName, "IIsApplicationPool");
                findPool.Invoke("Recycle", null);
                appPool.CommitChanges();
                appPool.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        #endregion

        #region 判断端口是否被占用
        /// <summary>
        /// 判断端口是否被占用
        /// </summary>
        /// <param name="port">端口号</param>
        /// <returns></returns>
        public  bool PortInUse(int port)
        {
            bool inUse = false;

            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (IPEndPoint endPoint in ipEndPoints)
            {
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            }
            return inUse;
        }
        #endregion

    }
}
